// initiates animation
window.requestAnimFrame = (function(){
	return  window.requestAnimationFrame   ||
			window.webkitRequestAnimationFrame ||
			window.mozRequestAnimationFrame    ||
			window.oRequestAnimationFrame      ||
			window.msRequestAnimationFrame     ||
			function(/* function */ callback, /* DOMElement */ element){
				console.log("using timeout fallback");
				return window.setTimeout(callback, 1000 / 60);
			};
})();
canvasAnimate = function (animationStep) {
	var self = this;
	return window.requestAnimFrame( animationStep );	
}
function Animation3D(){
	this.status = 0;
	this.execute = function(){
	}
	this.animationStep = function(){
	}
}
Translate3D.prototype = new Animation3D();  
Translate3D.prototype.constructor=Translate3D;
function Translate3D(){
	this.speed = {x:0,y:0,z:0};
	this.distance = {x:0,y:0,z:0};
	this.lastTime = 0;
	this.order = 1;
	
	this.animationStep = function(){
		if(this.status==0){
			// stopped
			return;
		}
		var timeNow = new Date().getTime();				
		if (this.lastTime != 0) {
		  var elapsed = timeNow - this.lastTime;

		  this.distance.x += (this.speed.x * elapsed) / 1000.0;
		  this.distance.y += (this.speed.y * elapsed) / 1000.0;
		  this.distance.z += (this.speed.z * elapsed) / 1000.0;
		  
		  
		}
		this.lastTime = timeNow;
	}
	
	this.execute = function(shape){
	
		if(this.distance.x!=0 || this.distance.y!=0 || this.distance.z!=0){
			
			mat4.translate(shape.scene.mvMatrix, [this.distance.x, this.distance.y, this.distance.z]);
		}
	}
	
	this.stop = function(){		
		this.status = 0;
		this.lastTime = 0;
	}	
	
	this.start = function(){
		if(this.status==0){
			this.lastTime = 0;
			this.status = 1;
		}
	}
}

Rotate3D.prototype = new Animation3D();  
Rotate3D.prototype.constructor=Rotate3D;
function Rotate3D(){
	this.angle = {x:0,y:0,z:0};
	this.speed = {x:0,y:0,z:0};
	this.lastTime = 0;
	this.order = 1;
	
	this.animationStep = function(){
		if(this.status==0){
			// stopped
			return;
		}
		var timeNow = new Date().getTime();				
		if (this.lastTime != 0) {
		  var elapsed = timeNow - this.lastTime;

		  this.angle.x += (this.speed.x * elapsed) / 1000.0;
		  this.angle.y += (this.speed.y * elapsed) / 1000.0;
		  this.angle.z += (this.speed.z * elapsed) / 1000.0;
		  
		  
		}
		this.lastTime = timeNow;
	}
	
	this.execute = function(shape){
		mat4.rotate(shape.scene.mvMatrix, this.angle.x * Math.PI / 180, [-1, 0, 0]);
		mat4.rotate(shape.scene.mvMatrix, this.angle.y * Math.PI / 180, [0, -1, 0]);
		mat4.rotate(shape.scene.mvMatrix, this.angle.z * Math.PI / 180, [0, 0 , -1]);
	}
	this.stop = function(){		
		this.status = 0;
		this.lastTime = 0;
	}	
	
	this.start = function(){
		if(this.status==0){
			this.lastTime = 0;
			this.status = 1;
		}
	}
}

TranslateCamera3D.prototype = new Animation3D();  
TranslateCamera3D.prototype.constructor=TranslateCamera3D;
function TranslateCamera3D(scene){
	this.scene = scene;
	this.speed = {x:0,y:0,z:0};	
	this.lastTime = 0;
	this.order = 1;
	var self = this;
	this.animationStep = function(){
		if(this.status==0){
			// stopped
			return;
		}
		var timeNow = new Date().getTime();				
		if (self.lastTime != 0) {
		  var elapsed = timeNow - this.lastTime;			
		  self.scene.cameraPosition.x += (self.speed.x * elapsed) / 1000.0;
		  self.scene.cameraPosition.y += (self.speed.y * elapsed) / 1000.0;
		  self.scene.cameraPosition.z += (self.speed.z * elapsed) / 1000.0;
		}
		self.lastTime = timeNow;
	}
	
	this.execute = function(shape){	
		return;
		// mat4.translate(shape.scene.mvMatrix, [-shape.scene.cameraPosition.x, -shape.scene.cameraPosition.y, -shape.scene.cameraPosition.z]);		
	}
	
	this.stop = function(){		
		this.status = 0;
		this.lastTime = 0;
	}	
	
	this.start = function(){	
		if(this.status==0){
			this.lastTime = 0;
			this.status = 1;
		}
	}
}

RotateCamera3D.prototype = new Animation3D();  
RotateCamera3D.prototype.constructor=RotateCamera3D;
function RotateCamera3D(scene){
	this.scene = scene;	
	this.speed = {x:0,y:0,z:0};
	this.lastTime = 0;
	this.order = 1;
	
	this.animationStep = function(){	
		if(this.status==0){
			// stopped
			return;
		}
		var timeNow = new Date().getTime();				
		if (this.lastTime != 0) {
		  var elapsed = timeNow - this.lastTime;

		  this.scene.cameraAngles.x += (this.speed.x * elapsed) / 1000.0;
		  this.scene.cameraAngles.y += (this.speed.y * elapsed) / 1000.0;
		  this.scene.cameraAngles.z += (this.speed.z * elapsed) / 1000.0;
		  
		  
		}
		this.lastTime = timeNow;
	}
	
	this.execute = function(shape){
		return;
		// mat4.rotate(shape.scene.mvMatrix, this.scene.cameraAngles.x * Math.PI / 180, [-1, 0, 0]);
		// mat4.rotate(shape.scene.mvMatrix, this.scene.cameraAngles.y * Math.PI / 180, [0, -1, 0]);
		// mat4.rotate(shape.scene.mvMatrix, this.scene.cameraAngles.z * Math.PI / 180, [0, 0 , -1]);
	}
	this.stop = function(){		
		this.status = 0;
		this.lastTime = 0;
	}	
	
	this.start = function(){	
		if(this.status==0){
			this.lastTime = 0;
			this.status = 1;
		}
	}
}

function Animation3DContext(scene){
	this.scene = scene;
	this.status = 0;
	this.animations = new Array();
	var self = this;
	this.stoppedCallback = null;
	this.add = function(animation){
		this.animations.push(animation);
	}
	this.animate = function(){
		if(self.status==0){
			if(typeof(self.stoppedCallback)=="function") self.stoppedCallback();
			return;
		}
		//console.log("animating"+self.status);
		if(self.animations && self.animations.length>0){
			for(var i=0;i<self.animations.length;i++)
				self.animations[i].animationStep();
			if(this.scene) this.scene.draw();
		}
		canvasAnimate(self.animate);
	}
	
	this.start = function(){
		this.status = 1;
		canvasAnimate(this.animate);		
	}
	
	this.stop = function(stoppedCallback){
		this.stoppedCallback = stoppedCallback;
		this.status = 0;
	}
}